package com.springsummer.information.green.beans;


import com.springsummer.information.green.annotation.*;
import com.springsummer.information.green.io.NormalScanService;
import com.springsummer.information.green.io.ScanService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;

public class ClassPathBeanDefinitionReaderScanner implements BeanDefinitionReader {


    private BeanDefinitionRegistry registry;

    private ScanService scanService;

    public ClassPathBeanDefinitionReaderScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
        this.scanService = new NormalScanService();
    }

    ClassPathBeanDefinitionScanner getSpringa() {
        AnnotationConfigApplicationContext annotationConfigApplicationContext;

        return null;
    }


    @Override
    public BeanDefinitionRegistry getBeanDefinitionRegistry() {
        return registry;
    }

    @Override
    public int loadBeanDefinitions(String location) throws Exception {
        Collection<BeanDefinition> beanDefinitionCollection = loadBeanDefinitionsInfo(location);
        int count = beanDefinitionCollection.size();
        return count;
    }

    @Override
    public Collection<BeanDefinition> loadBeanDefinitionsInfo(String location) throws Exception {
        Collection<BeanDefinition> beanDefinitionCollection = null;
        if (location.contains(",")) {
            String[] basePackages = location.split(",");
            beanDefinitionCollection = scan(basePackages);
        } else {
            beanDefinitionCollection = scan(location);
        }

        if (beanDefinitionCollection != null && !beanDefinitionCollection.isEmpty()) {
            for (BeanDefinition beanDefinition : beanDefinitionCollection) {
                //reg
                getBeanDefinitionRegistry().registerBeanDefinition(beanDefinition.getBeanId(), beanDefinition);
            }
        }

        return beanDefinitionCollection;
    }

    public Collection<BeanDefinition> scan(String... basePackages) {

        //doScan(basePackages);
        Collection<BeanDefinition> beanDefinitionCollection = new ArrayList<>(256);
        Set<BeanDefinition> beanDefinitionSet = doScan(basePackages);
        beanDefinitionCollection.addAll(beanDefinitionSet);

        return beanDefinitionCollection;
    }

    protected Set<BeanDefinition> doScan(String... basePackages) {
        try {
            Set<BeanDefinition> beanDefinitionSet = scanCandidateComponents(basePackages);
            return beanDefinitionSet;
        } catch (Exception e) {
            //throw new RuntimeException(e);
            return new LinkedHashSet<>();
        }
    }

    public Collection<String> doScanClassNames(String... basePackages) {
        return scanService.scanPackages(basePackages);
    }


    private Set<BeanDefinition> scanCandidateComponents(String... basePackages) throws Exception {
        Set<BeanDefinition> datasSet = new LinkedHashSet<>();
        Collection<String> scanedClassNames = doScanClassNames(basePackages);
        for (String name : scanedClassNames) {

            Class<?> clazz = Class.forName(name);

            boolean isCandidate = isCandidateComponent(clazz);

            if (isCandidate) {
                BeanDefinition beanDefinition = generateBeanDefinition(name, clazz);

                datasSet.add(beanDefinition);
            }

        }

        return datasSet;
    }

    private BeanDefinition generateBeanDefinition(String name, Class<?> clazz) {
        String clazzSimpleName = name.substring(name.lastIndexOf(".")+1, name.length());
        //String scopeName=getScopeName(clazz);
        StringBuilder beanSimpleName=new StringBuilder();
        beanSimpleName.append(Character.toLowerCase(clazzSimpleName.charAt(0)));
        beanSimpleName.append(clazzSimpleName.substring(1));

        //ScannedGenericBeanDefinition scannedGenericBeanDefinition=new ScannedGenericBeanDefinition();
        String beanId = beanSimpleName.toString();
        String beanName = beanId;
        String beanClassName = name;
        String scopeName = getScopeName(clazz);
        boolean singletonFlag = scopeName.equals("singleton") ? true : false;
        boolean prototypeFlag = scopeName.equals("prototype") ? true : false;
        ScannedGenericBeanDefinition scannedGenericBeanDefinition = new ScannedGenericBeanDefinition(beanId, beanClassName, beanName, scopeName, "", "", "", "", singletonFlag, prototypeFlag);
        return scannedGenericBeanDefinition;
    }

    //isCandidateComponent
    private boolean isCandidateComponent(Class<?> clazz) {
        boolean isCandidate = false;
        try {


            boolean isComponent = clazz.isAnnotationPresent(Component.class);
            boolean isRepository = clazz.isAnnotationPresent(Repository.class);
            boolean isService = clazz.isAnnotationPresent(Service.class);
            boolean isController = clazz.isAnnotationPresent(Controller.class);
            if (isComponent || isRepository || isService || isController) {
                isCandidate = true;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return isCandidate;
    }

    private String getScopeName(Class<?> clazz) {
        String scopeName = "singleton";
        if (clazz.isAnnotationPresent(Scope.class)) {
            String scopeTemp = clazz.getAnnotation(Scope.class).scopeName();
            if (!"".equals(scopeTemp)) {
                scopeName = scopeTemp;
            }
        }
        return scopeName;
    }

}